package com.lblin.method.adt;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.Element;

import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;

import com.xiaoleilu.hutool.io.FileUtil;
import com.xiaoleilu.hutool.util.StrUtil;

public class LoadClass {

	private static ASTParser parser;
	private static ASTVisitor visitor;
	private static ASTVisitor visitorMethod;

	private static void init() {
		parser = ASTParser.newParser(AST.JLS9); // 设置Java语言规范版本
		parser.setKind(ASTParser.K_COMPILATION_UNIT);// 所需解析的代码的类型
		parser.setResolveBindings(true);
		parser.setBindingsRecovery(true);
		parser.setEnvironment(null, null, null, true);

		Map<String, String> compilerOptions = JavaCore.getOptions();
		compilerOptions.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_8); // 设置Java语言版本
		compilerOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8);
		compilerOptions.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8);
		parser.setCompilerOptions(compilerOptions); // 设置编译选项
	}

	private static String source_path;

	public static void load(List<File> files, String projectPath) {

		source_path = projectPath;

		createVistor();

		loopByLevel(files, visitor);
	}

	private static CompilationUnit createAST(File file) {

		init();
		// 当前类名
		String className = file.getName().replace(".java", "");
		parser.setUnitName(className);
		String content = FileUtil.readString(file, "UTF-8");// 读取文件
		char[] src = content.toCharArray();
		parser.setSource(src);// 设置将要解析的字符数组
		CompilationUnit cu = (CompilationUnit) parser.createAST(null);// 将上面的字符数组解析后转换成对象；
		return cu;

	}

	private static void loopByLevel(List<File> files, ASTVisitor vi) {
		for (File file : files) {

			CompilationUnit cu = createAST(file);
			// 开始代码分析
			startAnalysis(cu, vi);
			// 分析完将本次分析的源码中的import类清空
			keyImports = new HashMap<String, String>();
		}
		// --------上层分析完毕---------
		// 开始递归分析方法
		List<File> newfiles = new LinkedList<File>();
		for (String key : notDeal) {
			String className = key.split(":")[0];
			//判断当前类是否子类
			className = filterChild(className);
			File file = new File(source_path + "/" + className.replace('.', '/') + ".java");
			if (file.exists()) {
				newfiles.add(file);
			}
		}
		if (newfiles.size() > 0) {
			loopByLevel(newfiles, visitorMethod);
		}
	}

	private static String filterChild(String className) {
		String newClassName = "";
		String[] classNames = className.split("\\.");
		for(int i = classNames.length-2;i>=0;i--) {//从倒数第二个字母开始判断
			String clazz = classNames[i];
			char f = clazz.charAt(0);
			char F = clazz.toUpperCase().charAt(0);
			
			if(F==f) {//当前是类而不是包
				//do nothing;
			}else {
				for(int j=0;j<=i+1;j++) {
					newClassName+=classNames[j]+".";
				}
				newClassName = newClassName.substring(0, newClassName.length()-1);
				break;
			}
		}
		return newClassName;
	}

	private static void startAnalysis(CompilationUnit cu, ASTVisitor vi) {
		cu.accept(vi);
	}

	private static Set<String> alreadyDeal = new HashSet<String>();

	private static Set<String> notDeal = new HashSet<String>();

	/**
	 * 是否处理过
	 * 
	 * @param classMethod
	 * @return
	 */
	private static boolean isDeal(String classMethod) {
		int oldsize = alreadyDeal.size();
		alreadyDeal.add(classMethod);
		int newsize = alreadyDeal.size();
		if (oldsize == newsize) {
			return true;
		}

		return false;
	}

	private static void createVistor() {

		ASTVisitor visitorNext = new ASTVisitor() {

			@Override
			public boolean visit(MethodInvocation mi) {
				// System.out.println("----------方法调用-----------");
				// System.out.println(mi.getName());//方法名

				Expression exp = mi.getExpression();
				String className = null;
				if (exp != null) {
					ITypeBinding itype = mi.getExpression().resolveTypeBinding();
					if (itype != null) {
						className = itype.getQualifiedName();
						String clazz = className.substring(className.lastIndexOf('.') + 1);
						if (keyImports.get(clazz) != null && !keyImports.get(clazz).equals(className)) {
							className = keyImports.get(clazz);
						}
					} else {
						className = keyImports.get(mi.getExpression().toString());
						if(StrUtil.isEmpty(className)) {//还是空的情况获取被调用方法左侧最近的new关键字的类
		        			String expression = mi.getExpression().toString();
		        			expression = expression.substring(expression.lastIndexOf("new ")+4); 
		        			expression = expression.substring(0, expression.indexOf("("));
		        			className = keyImports.get(expression.replace(" ", ""));
		        		}
					}
				} else {
					IMethodBinding mb = mi.resolveMethodBinding();// 当前方法的调用者
					className = mb.getDeclaringClass().getQualifiedName();
				}
				String key = className + ":" + mi.getName() + ":" + mi.arguments().size();
				if (!isDeal(key)) {
					// 继续遍历这个新的类和方法
					notDeal.add(key);
					if (CheckMethodUser.methodUser.get(key) == null) {
						CheckMethodUser.methodUser.put(key, new HashSet<String>());
					}
					CheckMethodUser.methodUser.get(key).add(preMethod);

				}

				return true;
			}
		};

		// 只遍历Method注解
		visitor = new ASTVisitor() {
			@Override
			public boolean visit(ImportDeclaration node) {
				// System.out.println("----------import-----------");
				String className = node.getName().getFullyQualifiedName();
				keyImports.put(className.substring(className.lastIndexOf(".") + 1), className);
				return true;
			}

			@Override
			public boolean visit(MethodDeclaration node) {
				List asd = node.modifiers();
				for (Object t : asd) {
					if (t instanceof Annotation) {// 是注解
						if ("Method".equals(((Annotation) t).getTypeName().getFullyQualifiedName())) {
							String key = node.resolveBinding().getDeclaringClass().getQualifiedName() + ":"
									+ node.getName() + ":" + node.parameters().size();
							alreadyDeal.add(key);
							preMethod = key;
							node.accept(visitorNext);
							break;
						}
					}
				}
				return true;
			}
		};

		visitorMethod = new ASTVisitor() {

			@Override
			public boolean visit(ImportDeclaration node) {
				// System.out.println("----------import-----------");
				String className = node.getName().getFullyQualifiedName();
				keyImports.put(className.substring(className.lastIndexOf(".") + 1), className);
				return true;
			}

			@Override
			public boolean visit(MethodDeclaration node) {
				String name = node.getName().getFullyQualifiedName();
				String key = node.resolveBinding().getDeclaringClass().getQualifiedName() + ":" + name + ":"
						+ node.parameters().size();
				if (notDeal.contains(key)) {//
					preMethod = key;
					notDeal.remove(key);
					node.accept(visitorNext);
				}
				return true;
			}
		};
	}

	public static Map<String, String> keyImports = new HashMap<String, String>();

	private static String preMethod;

	public static void main(String[] args) {
		List<File> files = new LinkedList<File>();
		files.add(new File("/E:/Workspaces/other/testMethodClean/src/main/java/com/test/web/method/GlobleMethod.java"));
		load(files, "/E:/Workspaces/other/testMethodClean/src/main/java");
	}
}
